#include "stdafx.h"
#include "SettingsTable.h"

SettingsList::SettingsList( ){}
SettingsList::SettingsList( const SettingsList& rk ) : mList(rk.mList){}
SettingsList::~SettingsList( ){ clear(); }

void SettingsList::reloadSettings()
{
	for( auto i=mList.begin(); i!=mList.end(); i++ ) (*i)->reloadSetting();
}
void SettingsList::saveSettings()
{
	for( auto i=mList.begin(); i!=mList.end(); i++ ) (*i)->saveSetting();
}

bool SettingsList::hasItem( const std::string &name ) const{
	for( auto i=mList.begin(); i!=mList.end(); i++ )
		if( (*i)->getName() == name ) return true;
	return false;
}
	
SettingsList::ItemList::iterator SettingsList::findItem( const std::string &name )
{
	for( auto i=mList.begin(); i!=mList.end(); i++ )
		if( (*i)->getName() == name ) return i;
	return mList.end();
}
SettingsList::ItemList::const_iterator SettingsList::findItem( const std::string &name ) const
{
	for( auto i=mList.begin(); i!=mList.end(); i++ )
		if( (*i)->getName() == name ) return i;
	return mList.end();
}

SettingsItem* SettingsList::addItem( SettingsItem*itm )
{
	if( hasItem( itm->getName() ) ){ if( itm ) delete itm, itm = NULL; }
	else mList.push_back( itm );
	return itm;
}
void SettingsList::clear()
{
	for( auto i=mList.begin(); i!=mList.end(); i++ ) delete (*i), (*i) = NULL;
	mList.clear();
}
bool SettingsList::removeItem( const std::string &name ){
	return removeItem( findItem( name ) );
}
bool SettingsList::removeItem( SettingsList::ItemList::iterator itor ){
	if( itor == mList.end() ) return false;
	delete (*itor), (*itor) = NULL;
	mList.erase( itor );
	return true;
}
size_t SettingsList::size() const{ return mList.size(); }
bool SettingsList::empty() const{ return mList.empty(); }

SettingsTable::SettingsTable( QWidget * parent ) : QTableWidget( parent )
{
	clearContents();
	setColumnCount( 2 );
	setHorizontalHeaderLabels( QStringList("Name") << QString("Value") );
	horizontalHeader()->setStretchLastSection( true );
	horizontalHeader()->setVisible( true );
	verticalHeader()->setVisible( false );
	setSelectionBehavior( QTableWidget::SelectRows );
	setSelectionMode( QTableWidget::SingleSelection );
}
SettingsTable::~SettingsTable(){ clear(); }

void SettingsTable::reloadSettings()
{
	mList.reloadSettings();
}
void SettingsTable::saveSettings()
{
	mList.saveSettings();
}
void SettingsTable::_makeEnoughRows()
{
	size_t size = mList.size();
	size_t id = ((!mList.empty())?(size-1):0);
	if( rowCount() < size ) setRowCount( size );
}
size_t SettingsTable::_currentRow(){ return ((!mList.empty())?(mList.size()-1):0); }
void SettingsTable::connect( SettingsItem * itm )
{
		QObject::connect( 
			itm, 
			SIGNAL( itemChanged( const std::string &, const std::string & ) ), 
			this, 
			SIGNAL( settingChanged( const std::string &, const std::string & ) ) 
		);
}

SettingsItem * SettingsTable::findSetting( const std::string &name ){
	if( !hasSetting(name) ) return NULL;
	return *mList.findItem(name);
}
SettingsTextItem* SettingsTable::addSetting( const std::string &name, const std::string &value, bool modifiable )
{
	return _addRow( new SettingsTextItem( name, value, modifiable, this ) );
}
SettingsTableItem* SettingsTable::addSettingsTable( const std::string &name, bool modifiable )
{
	SettingsTableItem * itm = new SettingsTableItem( name, "", modifiable, this );
	itm->table()->setContentsMargins( 0,0,0,0 );
	itm->table()->horizontalHeader()->setVisible( false );
	return _addRow( itm );
}
SettingsTableItem* SettingsTable::addSetting( const std::string &name, bool modifiable )
{
	return _addRow( new SettingsTableItem( name, "", modifiable, this ) );
}
SettingsTextItem* SettingsTable::addSetting( const std::string &name, const char* value, bool modifiable )
{
	return _addRow( new SettingsTextItem( name, std::string(value), modifiable, this ) );
}
SettingsTextItem* SettingsTable::addSetting( const std::string &name, const QString &value, bool modifiable )
{
	return _addRow( new SettingsTextItem( name, std::string(value.toAscii().data()), modifiable, this ) );
}
SettingsComboItem* SettingsTable::addSetting( const std::string &name, const Lit::StringList &value, bool modifiable )
{
	return _addRow( new SettingsComboItem( name, value, modifiable, this ) );
}
SettingsTextItem* SettingsTable::addSetting( const std::string &name, const Ogre::Real& value, bool modifiable )
{
	return _addRow( new SettingsTextItem( name, Ogre::StringConverter::toString(value), modifiable, this ) );
}
SettingsDegreeItem* SettingsTable::addSetting( const std::string &name, const Ogre::Radian& value, bool modifiable )
{
	return _addRow( new SettingsDegreeItem( name, value, modifiable, this ) );
}
SettingsCheckboxItem* SettingsTable::addSetting( const std::string &name, bool value, bool modifiable )
{
	return _addRow( new SettingsCheckboxItem( name, value, modifiable, this ) );
}
SettingsVectorItem* SettingsTable::addSetting( const std::string &name, const Ogre::Vector3& value, bool inline_, bool modifiable )
{
	return _addRow( new SettingsVectorItem( name, value, modifiable, inline_, this ) );
}

SettingsDegreeItem* SettingsTable::addSetting( const std::string &name, const Ogre::Degree& value, bool modifiable )
{
	return _addRow( new SettingsDegreeItem( name, value, modifiable, this ) );
}

SettingsColorItem* SettingsTable::addSetting( const std::string &name, const Ogre::ColourValue& value, bool modifiable )
{
	return _addRow( new SettingsColorItem( name, value, modifiable, this ) );
}

SettingsColorItem* SettingsTable::addSetting( const std::string &name, const QColor& value, bool modifiable )
{
	return _addRow( new SettingsColorItem( name, value, modifiable, this ) );
}

SettingsQuaternionItem* SettingsTable::addSetting( const std::string &name, const Ogre::Quaternion& value, bool modifiable )
{
	return _addRow( new SettingsQuaternionItem( name, value, modifiable, this ) );
}
void SettingsTable::removeSetting( const std::string &name )
{
	if( !mList.hasItem( name ) ) return;
	(*mList.findItem(name))->disconnect();
	mList.removeItem( name );
}

bool SettingsTable::hasSetting( const std::string &name ) const
{
	return mList.hasItem( name );
}

void SettingsTable::clear(){ 
	mList.clear(); 
	clearContents();
}
size_t SettingsTable::size() const{ return mList.size(); }
bool SettingsTable::empty() const{ return mList.empty(); }

SettingsWidget::Page::Page( ) : id(0), table(0), tabWidget(0), name(""){}
SettingsWidget::Page::Page( const Page &rk ){ tabWidget = rk.tabWidget; id = rk.id; name = rk.name; table = rk.table; }
SettingsWidget::Page::~Page(){ destroy(); }
SettingsWidget::Page& SettingsWidget::Page::operator = ( const SettingsWidget::Page &rk ){ tabWidget = rk.tabWidget; id = rk.id; name = rk.name; table = rk.table; return *this; }

void SettingsWidget::Page::create( const std::string &name_, QTabWidget * widget )
{
	tabWidget = widget;
	name = name_;
	table = new SettingsTable(widget);
	id = tabWidget->addTab( table, name.c_str() );
	tabWidget->setTabText( id, name.c_str() );
}
void SettingsWidget::Page::destroy()
{
	if( tabWidget )
	{
		tabWidget->removeTab( id );
		if( table ) delete table, table = NULL;
	}
	table = NULL;
	id = 0;
	tabWidget = NULL;
}

void SettingsWidget::_settingChanged( const std::string &_name, const std::string &val )
{
	QObject* sendr = sender();
	for( auto i=mTabList.begin(); i!=mTabList.end(); i++ )
	{
		if( sendr == (*i)->table ){
			emit settingChanged( (*i)->name, _name, val );
			return;
		}
	}
}

SettingsWidget::SettingsWidget( QWidget * parent ) : QWidget( parent )
{
	mLay = new QVBoxLayout( this );
	setLayout(mLay);
	mTabs = new QTabWidget(this);
	mTabs->setContentsMargins(0,0,0,0);
	mLay->setContentsMargins(0,0,0,0);
	mLay->addWidget(mTabs);

	connect( mTabs, SIGNAL(currentChanged(int)), this, SIGNAL(currentPageChanged(int)) );
}
SettingsWidget::~SettingsWidget( )
{
	clearPages();
}

int SettingsWidget::findPageId( const std::string &name ){ for( auto i=mTabList.begin(); i!=mTabList.end(); i++ ) if( (*i)->name == name ) return(*i)->id; return -1; }
std::string SettingsWidget::findPageName( int id ){ for( auto i=mTabList.begin(); i!=mTabList.end(); i++ ) if( (*i)->id == id ) return (*i)->name; return ""; }

void SettingsWidget::reloadPages(){ for( auto i=mTabList.begin(); i!=mTabList.end(); i++ ) (*i)->table->reloadSettings(); }
void SettingsWidget::savePages(){ for( auto i=mTabList.begin(); i!=mTabList.end(); i++ ) (*i)->table->reloadSettings(); }

void SettingsWidget::savePage( const std::string &name ){if( hasPage(name) ) (*findPage(name))->table->saveSettings(); }
void SettingsWidget::reloadPage( const std::string &name ){if( hasPage(name) ) (*findPage(name))->table->reloadSettings(); }

SettingsWidget::Page* SettingsWidget::createPage( const std::string &name )
{
	Page *p = new Page;
	p->create( name, mTabs );
	connect( p->table, SIGNAL(settingChanged(const std::string &, const std::string &)), this, SLOT(_settingChanged(const std::string &, const std::string &)) );
	mTabList.push_back(p);
	return mTabList.back();
}
void SettingsWidget::removePage( const std::string &name, bool erase )
{
	list_t::iterator i=findPage( name );
	if( i== mTabList.end() ) return;
	delete (*i), (*i) = NULL;
	if( erase ) mTabList.erase( i );
}
bool SettingsWidget::hasPage( const std::string &name ) const
{
	for( auto i=mTabList.begin(); i!=mTabList.end(); i++ )
	{
		if( (*i)->name == name ) return true;
	}
	return false;
}
SettingsWidget::list_t::iterator SettingsWidget::findPage( const std::string &name )
{
	for( auto i=mTabList.begin(); i!=mTabList.end(); i++ )
	{
		if( (*i) &&  (*i)->name == name ) return i;
	}
	return mTabList.end();
}
SettingsWidget::list_t::const_iterator SettingsWidget::findPage( const std::string &name ) const
{
	for( auto i=mTabList.begin(); i!=mTabList.end(); i++ )
	{
		if( (*i)->name == name ) return i;
	}
	return mTabList.end();
}
void SettingsWidget::clearPages()
{
	for( auto i=mTabList.begin(); i!=mTabList.end(); i++ )
	{
		mTabs->removeTab( (*i)->id );
		if( *i ) delete (*i), (*i) = NULL;
	}
	mTabList.clear();
}